import psutil
import time
import logging
from typing import List, Dict, Any
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QTableWidgetItem, QHeaderView, QProgressDialog
from PyQt6.QtCore import Qt, QThread, pyqtSignal, QTimer
from PyQt6.QtGui import QFont, QColor
from qfluentwidgets import (CardWidget, BodyLabel, FluentIcon, PushButton, InfoBar, InfoBarPosition, SearchLineEdit,
                            ComboBox, MessageBox, TableWidget, StrongBodyLabel, ProgressBar, TitleLabel,
                            PrimaryPushButton)
from common.widgets.info_card import InfoCard  # Assuming this is available

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)


class ProcessWorker(QThread):
    """后台线程，用于采集进程信息"""
    data_updated = pyqtSignal(list, dict)
    error_occurred = pyqtSignal(str)
    # 新增信号，表示数据采集开始和结束
    collection_started = pyqtSignal()
    collection_finished = pyqtSignal()

    def __init__(self, update_interval=5):
        super().__init__()
        self.running = True
        self.update_interval = update_interval
        self.last_update = 0

    def set_update_interval(self, interval):
        """设置更新间隔"""
        self.update_interval = interval

    def stop(self):
        """停止线程"""
        self.running = False

    def run(self):
        """线程主循环"""
        while self.running:
            try:
                current_time = time.time()
                if current_time - self.last_update >= self.update_interval:
                    self.collection_started.emit()  # 发送采集开始信号
                    processes, stats = self.collect_processes()
                    self.data_updated.emit(processes, stats)
                    self.last_update = current_time
                    self.collection_finished.emit()  # 发送采集结束信号
                time.sleep(1)
            except Exception as e:
                logger.error(f"Process collection error: {str(e)}")
                self.error_occurred.emit(f"进程采集错误: {str(e)}")

    def collect_processes(self):
        """采集进程信息"""
        processes = []
        stats = {'total': 0, 'running': 0, 'sleeping': 0, 'zombie': 0, 'stopped': 0,
                 'high_cpu': 0, 'high_memory': 0, 'suspicious': 0}

        try:
            for proc in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_info', 'status']):
                try:
                    info = proc.info
                    if info['name'].lower() == 'system idle process' and info['pid'] == 0:  # 通常Windows下System Idle Process的PID是0
                        continue
                    memory_mb = info['memory_info'].rss / (1024 ** 2) if info['memory_info'] else 0
                    cpu_percent = info['cpu_percent'] or 0

                    process_info = {
                        'pid': info['pid'],
                        'name': info['name'] or f"PID-{info['pid']}",
                        'cpu_percent': cpu_percent,
                        'memory_mb': memory_mb,
                        'status': info['status'] or 'unknown',
                    }

                    processes.append(process_info)

                    # 统计信息
                    stats['total'] += 1
                    status = process_info['status']
                    if status in stats:
                        stats[status] += 1
                    if cpu_percent > 30:
                        stats['high_cpu'] += 1
                    if memory_mb > 500:
                        stats['high_memory'] += 1
                    if cpu_percent > 30 or memory_mb > 500:
                        stats['suspicious'] += 1

                except (psutil.NoSuchProcess, psutil.AccessDenied):
                    continue

        except Exception as e:
            logger.error(f"Error collecting processes: {e}")

        return processes, stats


class ProcessManager(QWidget):
    """优化后的进程管理器"""

    def __init__(self):
        super().__init__()
        self.MAX_PAGE_SIZE = 30  # 每页显示数量
        self.processes = []
        self.filtered_processes = []
        self.current_page = 0
        self.is_updating = False
        self.worker = None  # 将worker改为实例变量
        self.is_page_visible = False  # 添加页面可见状态标记

        # 添加更新定时器，避免频繁更新UI
        self.ui_update_timer = QTimer()
        self.ui_update_timer.timeout.connect(self.delayed_ui_update)
        self.ui_update_timer.setSingleShot(True)
        self.pending_data = None

        self.progress_dialog = None  # 进度对话框，在需要时才创建

        self.init_ui()

    def showEvent(self, event):
        """页面显示时启动定时刷新"""
        super().showEvent(event)
        self.is_page_visible = True
        logger.info("进程管理页面显示，开始启动监控")
        self.start_worker()

    def hideEvent(self, event):
        """页面隐藏时停止定时刷新"""
        super().hideEvent(event)
        self.is_page_visible = False
        logger.info("进程管理页面隐藏，停止监控")
        self.stop_worker()

    def start_worker(self):
        """启动工作线程"""
        if not self.is_page_visible:
            logger.info("页面不可见，跳过启动工作线程")
            return

        if self.worker is None or not self.worker.isRunning():
            self.worker = ProcessWorker(update_interval=5)
            self.worker.data_updated.connect(self.on_data_updated)
            self.worker.error_occurred.connect(self.handle_error)
            self.worker.collection_started.connect(self.show_loading_indicator)  # 连接开始信号
            self.worker.collection_finished.connect(self.hide_loading_indicator)  # 连接结束信号
            self.worker.start()
            logger.info("进程监控线程已启动")

    def stop_worker(self):
        """停止工作线程"""
        if self.worker and self.worker.isRunning():
            self.worker.stop()
            self.worker.wait(3000)  # 等待最多3秒
            logger.info("进程监控线程已停止")
        self.hide_loading_indicator()  # 确保关闭加载提示

    def create_progress_dialog(self):
        """创建进度对话框（延迟创建）"""
        if self.progress_dialog is None:
            self.progress_dialog = QProgressDialog("正在加载进程数据...", None, 0, 0, self)
            self.progress_dialog.setWindowTitle("加载中")
            self.progress_dialog.setWindowModality(Qt.WindowModality.ApplicationModal)
            self.progress_dialog.setCancelButton(None)  # 禁用取消按钮
            self.progress_dialog.setAutoClose(True)
            self.progress_dialog.setAutoReset(True)
            self.progress_dialog.hide()  # 默认隐藏
            self.progress_dialog.setStyleSheet("""
                        QProgressBar {
                            text-align: center;
                            border-radius: 1px;
                            height: 3px;
                            background-color: #f0f0f0;
                        }
                        QProgressBar::chunk {
                            background-color: #4CAF50;
                            border-radius: 1px;
                        }
                        QLabel {
                            text-align: center;
                            padding: 1px;
                        }
                    """)

    def init_ui(self):
        """初始化UI"""
        layout = QVBoxLayout(self)
        layout.setContentsMargins(20, 20, 20, 20)
        layout.setSpacing(15)

        # 标题
        title = TitleLabel("进程管理")
        layout.addWidget(title)

        # 统计卡片
        stats_card = self.create_stats_section()
        layout.addWidget(stats_card)

        # 控制面板
        control_card = self.create_control_panel()
        layout.addWidget(control_card)

        # 进程表格
        table_card = self.create_table_section()
        layout.addWidget(table_card)

    def show_loading_indicator(self):
        """显示加载指示器"""
        # 只有在页面可见时才显示加载指示器
        if not self.is_page_visible:
            return

        # 延迟创建进度对话框
        self.create_progress_dialog()

        if not self.progress_dialog.isVisible():
            self.progress_dialog.setLabelText("正在采集进程数据...")
            self.progress_dialog.show()
            self.progress_dialog.setValue(0)  # 重置进度条

    def hide_loading_indicator(self):
        """隐藏加载指示器"""
        if self.progress_dialog and self.progress_dialog.isVisible():
            self.progress_dialog.hide()

    def create_stats_section(self):
        """创建统计卡片区域"""
        card = CardWidget()
        layout = QHBoxLayout(card)
        layout.setContentsMargins(20, 15, 20, 15)
        layout.setSpacing(15)

        self.total_card = InfoCard("总进程数", "0", "个", icon="📊", color="#2196F3")
        self.running_card = InfoCard("运行中", "0", "个", icon="🏃", color="#4CAF50")
        self.suspicious_card = InfoCard("异常进程", "0", "个", icon="🚨", color="#F44336")
        self.high_cpu_card = InfoCard("高CPU占用", "0", "个", icon="🔥", color="#FF9800")
        self.high_memory_card = InfoCard("高内存占用", "0", "个", icon="💾", color="#9C27B0")  # Added High Memory Card

        layout.addWidget(self.total_card)
        layout.addWidget(self.running_card)
        layout.addWidget(self.suspicious_card)
        layout.addWidget(self.high_cpu_card)
        layout.addWidget(self.high_memory_card)  # Add new card to layout
        return card

    def create_control_panel(self):
        """创建控制面板"""
        control_card = CardWidget()
        control_layout = QHBoxLayout(control_card)
        control_layout.setContentsMargins(15, 12, 15, 12)
        control_layout.setSpacing(10)

        self.search_input = SearchLineEdit()
        self.search_input.setPlaceholderText("搜索进程名称或PID...")
        self.search_input.setFixedWidth(250)
        self.search_input.textChanged.connect(self.on_search_changed)

        self.filter_combo = ComboBox()
        self.filter_combo.addItems(["显示全部", "高CPU占用", "高内存占用"])
        self.filter_combo.setFixedWidth(120)
        self.filter_combo.currentTextChanged.connect(self.on_filter_changed)

        self.refresh_interval_combo = ComboBox()
        self.refresh_interval_combo.addItems(["3秒", "5秒", "10秒"])
        self.refresh_interval_combo.setCurrentText("5秒")
        self.refresh_interval_combo.setFixedWidth(100)
        self.refresh_interval_combo.currentTextChanged.connect(self.on_refresh_interval_changed)

        self.refresh_btn = PushButton("立即刷新", icon=FluentIcon.SYNC)
        self.refresh_btn.clicked.connect(self.manual_refresh)

        control_layout.addWidget(self.search_input)
        control_layout.addWidget(self.filter_combo)
        control_layout.addWidget(BodyLabel("刷新:"))
        control_layout.addWidget(self.refresh_interval_combo)
        control_layout.addWidget(self.refresh_btn)
        control_layout.addStretch()

        return control_card

    def create_table_section(self):
        """创建表格区域"""
        card = CardWidget()
        layout = QVBoxLayout(card)
        layout.setContentsMargins(15, 15, 15, 15)

        self.table = TableWidget()
        self.table.setColumnCount(6)
        self.table.setHorizontalHeaderLabels(["PID", "进程名", "CPU(%)", "内存(MB)", "状态", "操作"])

        # 设置列宽
        header = self.table.horizontalHeader()
        header.setSectionResizeMode(0, QHeaderView.ResizeMode.ResizeToContents)
        header.setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch)
        header.setSectionResizeMode(2, QHeaderView.ResizeMode.ResizeToContents)
        header.setSectionResizeMode(3, QHeaderView.ResizeMode.ResizeToContents)
        header.setSectionResizeMode(4, QHeaderView.ResizeMode.ResizeToContents)
        header.setSectionResizeMode(5, QHeaderView.ResizeMode.Fixed)
        self.table.setColumnWidth(5, 200)

        self.table.setAlternatingRowColors(True)
        layout.addWidget(self.table)

        # 分页导航
        pagination_layout = QHBoxLayout()
        self.prev_page_btn = PushButton("上一页")
        self.prev_page_btn.clicked.connect(self.prev_page)
        self.next_page_btn = PushButton("下一页")
        self.next_page_btn.clicked.connect(self.next_page)
        self.page_label = StrongBodyLabel("第 1 页 / 共 1 页")

        pagination_layout.addWidget(self.prev_page_btn)
        pagination_layout.addWidget(self.page_label)
        pagination_layout.addWidget(self.next_page_btn)
        pagination_layout.addStretch()
        layout.addLayout(pagination_layout)

        return card

    def on_data_updated(self, processes: List[Dict], stats: Dict[str, Any]):
        """数据更新处理 - 使用延迟更新避免卡顿"""
        # 只有在页面可见时才处理数据更新
        if not self.is_page_visible:
            return

        # 即使worker发送了信号，这里也用timer再次延迟，避免在数据密集处理时阻塞UI
        self.pending_data = (processes, stats)

        if not self.ui_update_timer.isActive():
            self.ui_update_timer.start(50)  # 缩短延迟，更快响应数据

    def delayed_ui_update(self):
        """延迟UI更新"""
        if not self.pending_data or not self.is_page_visible:
            return

        processes, stats = self.pending_data
        self.pending_data = None

        self.is_updating = True  # 标记正在更新，避免重复触发

        self.processes = processes
        self.filter_processes()
        self.update_table()
        self.update_statistics(stats)

        self.is_updating = False

    def filter_processes(self):
        """应用过滤条件"""
        filter_text = self.search_input.text().lower()
        filter_type = self.filter_combo.currentText()

        filtered = self.processes.copy()

        # 搜索过滤
        if filter_text:
            filtered = [p for p in filtered
                        if filter_text in str(p['pid']) or filter_text in p['name'].lower()]

        # 类型过滤
        if filter_type == "高CPU占用":
            filtered = [p for p in filtered if p.get('cpu_percent', 0) > 30]
        elif filter_type == "高内存占用":
            filtered = [p for p in filtered if p.get('memory_mb', 0) > 500]

        self.filtered_processes = filtered
        self.update_pagination()

    def update_table(self):
        """更新表格显示 - 性能优化"""
        start_idx = self.current_page * self.MAX_PAGE_SIZE
        end_idx = min(start_idx + self.MAX_PAGE_SIZE, len(self.filtered_processes))
        displayed = self.filtered_processes[start_idx:end_idx]

        # 优化：只更新需要更新的行，并重用QTableWidgetItem
        self.table.setRowCount(len(displayed))

        for row, proc in enumerate(displayed):
            # PID
            self.set_table_item_and_color(row, 0, str(proc['pid']))

            # 进程名
            self.set_table_item_and_color(row, 1, proc['name'])

            # CPU
            cpu_text = f"{proc['cpu_percent']:.1f}"
            cpu_color = QColor()
            if proc['cpu_percent'] > 50:
                cpu_color = QColor("#D32F2F")
            elif proc['cpu_percent'] > 30:
                cpu_color = QColor("#F57C00")
            self.set_table_item_and_color(row, 2, cpu_text, cpu_color)

            # 内存
            memory_text = f"{proc['memory_mb']:.1f}"
            memory_color = QColor()
            if proc['memory_mb'] > 1000:
                memory_color = QColor("#D32F2F")
            elif proc['memory_mb'] > 500:
                memory_color = QColor("#F57C00")
            self.set_table_item_and_color(row, 3, memory_text, memory_color)

            # 状态
            status_text = self.get_status_display(proc.get('status', 'unknown'))
            self.set_table_item_and_color(row, 4, status_text)

            # 操作按钮 - 优化按钮创建
            self.create_action_buttons(row, proc['pid'])

    def set_table_item_and_color(self, row, col, text, color: QColor = QColor()):
        """设置表格项并根据需要设置颜色"""
        item = self.table.item(row, col)
        if item is None:
            item = QTableWidgetItem(text)
            self.table.setItem(row, col, item)
        else:
            item.setText(text)
        item.setForeground(color)
        item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)  # 居中对齐

    def create_action_buttons(self, row, pid):
        """创建操作按钮 - 减少按钮数量"""
        # 检查是否已存在按钮组件
        existing_widget = self.table.cellWidget(row, 5)
        if existing_widget is None:  # 如果不存在，则创建
            button_widget = QWidget()
            button_layout = QHBoxLayout(button_widget)
            button_layout.setContentsMargins(5, 2, 5, 2)
            button_layout.setSpacing(5)

            detail_btn = PushButton("详情")
            terminate_btn = PushButton("终止")

            button_layout.addWidget(detail_btn)
            button_layout.addWidget(terminate_btn)
            self.table.setCellWidget(row, 5, button_widget)
        else:  # 如果已存在，则获取并更新其信号连接
            button_widget = existing_widget
            button_layout = existing_widget.layout()
            detail_btn = button_layout.itemAt(0).widget()
            terminate_btn = button_layout.itemAt(1).widget()

        # 确保每次都重新连接信号，避免旧的连接累积导致多次触发
        try:
            detail_btn.clicked.disconnect()
        except TypeError:
            pass  # No existing connection
        detail_btn.clicked.connect(lambda: self.show_process_detail(pid))

        try:
            terminate_btn.clicked.disconnect()
        except TypeError:
            pass  # No existing connection
        terminate_btn.clicked.connect(lambda: self.terminate_process(pid))

    def update_statistics(self, stats: Dict[str, Any]):
        """更新统计信息"""
        self.total_card.update_value(f"{stats.get('total', 0)}")
        self.running_card.update_value(f"{stats.get('running', 0)}")
        self.suspicious_card.update_value(f"{stats.get('suspicious', 0)}")
        self.high_cpu_card.update_value(f"{stats.get('high_cpu', 0)}")
        self.high_memory_card.update_value(f"{stats.get('high_memory', 0)}")  # Update High Memory Card

    def update_pagination(self):
        """更新分页信息"""
        total_pages = max(1, (len(self.filtered_processes) + self.MAX_PAGE_SIZE - 1) // self.MAX_PAGE_SIZE)
        self.page_label.setText(f"第 {self.current_page + 1} 页 / 共 {total_pages} 页")
        self.prev_page_btn.setEnabled(self.current_page > 0)
        self.next_page_btn.setEnabled(self.current_page < total_pages - 1)

    def prev_page(self):
        """上一页"""
        if self.current_page > 0:
            self.current_page -= 1
            self.update_table()
            self.update_pagination()

    def next_page(self):
        """下一页"""
        total_pages = max(1, (len(self.filtered_processes) + self.MAX_PAGE_SIZE - 1) // self.MAX_PAGE_SIZE)
        if self.current_page < total_pages - 1:
            self.current_page += 1
            self.update_table()
            self.update_pagination()

    def get_status_display(self, status) -> str:
        """获取状态显示名称"""
        status_map = {
            'running': '运行', 'sleeping': '休眠', 'disk-sleep': '磁盘休眠',
            'stopped': '停止', 'zombie': '僵尸', 'dead': '死亡'
        }
        return status_map.get(str(status), '未知')

    def show_process_detail(self, pid: int):
        """显示进程详情"""
        try:
            # 尝试从当前过滤后的进程列表中查找该PID的进程信息
            # 如果找不到，则回退到直接从psutil获取，但会发出警告
            process_info_from_table = next((p for p in self.filtered_processes if p['pid'] == pid), None)

            if process_info_from_table:
                # 使用表格中的数据
                name = process_info_from_table['name']
                cpu_percent = process_info_from_table['cpu_percent']
                memory_mb = process_info_from_table['memory_mb']
                status = process_info_from_table['status']
                # 创建时间通常不会实时变化，可以重新获取或考虑存储
                try:
                    create_time = psutil.Process(pid).create_time()
                except (psutil.NoSuchProcess, psutil.AccessDenied):
                    create_time = 0  # 无法获取则设为0

            else:
                # 如果在当前表格数据中找不到，则直接从psutil获取
                # 但这可能会导致和表格当前显示的数据不一致，如果表格数据是旧的
                logger.warning(f"无法在当前表格数据中找到PID {pid}，将直接从psutil获取。")
                process = psutil.Process(pid)
                info = process.as_dict(attrs=['pid', 'name', 'cpu_percent', 'memory_info', 'status', 'create_time'])
                name = info['name']
                cpu_percent = info['cpu_percent'] or 0
                memory_mb = info['memory_info'].rss / (1024 ** 2) if info['memory_info'] else 0
                status = info['status']
                create_time = info['create_time']

            content = (
                f"PID: {pid}\n"
                f"名称: {name}\n"
                f"CPU: {cpu_percent:.1f}%\n"
                f"内存: {memory_mb:.1f} MB\n"
                f"状态: {self.get_status_display(status)}\n"
                f"创建时间: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(create_time))}"
            )
            msg_box = MessageBox("进程详情", content, self)
            msg_box.yesButton.setText("确定")
            msg_box.cancelButton.hide()
            msg_box.exec()
        except Exception as e:
            self.handle_error(f"显示进程详情失败: {str(e)}")

    def terminate_process(self, pid: int):
        """终止进程"""
        try:
            process = psutil.Process(pid)
            process_name = process.name()

            # 弹出确认对话框
            confirm_box = MessageBox("确认终止", f"确定要终止进程 {process_name} (PID: {pid}) 吗？", self)
            confirm_box.yesButton.setText("确定")
            confirm_box.cancelButton.setText("取消")
            if confirm_box.exec() == 1:
                process.terminate()
                InfoBar.success(
                    title="成功", content=f"进程 {process_name} (PID: {pid}) 已终止",
                    position=InfoBarPosition.TOP_RIGHT, duration=3000, parent=self
                )
                # 立即触发一次数据刷新，以便表格反映变化
                self.manual_refresh()
        except psutil.NoSuchProcess:
            self.handle_error(f"进程 {pid} 不存在或已被终止。")
        except psutil.AccessDenied:
            self.handle_error(f"权限不足，无法终止进程 {pid}。")
        except Exception as e:
            self.handle_error(f"终止进程失败: {str(e)}")

    def handle_error(self, error_msg: str):
        """处理错误"""
        InfoBar.error(
            title="错误", content=error_msg,
            position=InfoBarPosition.TOP_RIGHT, duration=3000, parent=self
        )

    def on_search_changed(self, text: str):
        """搜索改变时重置到第一页并触发刷新"""
        self.current_page = 0
        if not self.is_updating:
            self.filter_processes()
            self.update_table()

    def on_filter_changed(self, text: str):
        """筛选改变时重置到第一页并触发刷新"""
        self.current_page = 0
        if not self.is_updating:
            self.filter_processes()
            self.update_table()

    def on_refresh_interval_changed(self, text: str):
        """刷新频率改变"""
        if self.worker:
            interval = int(text.replace('秒', ''))
            self.worker.set_update_interval(interval)
            InfoBar.success(
                title="刷新间隔已更新", content=f"刷新间隔已设置为 {interval} 秒。",
                position=InfoBarPosition.TOP_RIGHT, duration=2000, parent=self
            )

    def manual_refresh(self):
        """手动刷新"""
        if not self.is_page_visible:
            logger.info("页面不可见，跳过手动刷新")
            return

        if self.worker:
            # 立即触发一次数据采集
            self.worker.last_update = 0
            # 立即启动worker，如果它没有运行
            if not self.worker.isRunning():
                self.start_worker()
            # 显示加载指示器
            self.show_loading_indicator()

    def closeEvent(self, event):
        """关闭事件"""
        self.is_page_visible = False
        self.stop_worker()
        self.hide_loading_indicator()  # 确保关闭加载提示
        event.accept()